package com.lock.redisLocks.ledixbinary;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

import com.lock.redisLocks.RedisHelper.ProviderConfigType;
import com.lock.redisLocks.RedisHelper.RedisConfigType;

import io.lettuce.core.RedisException;

public class LedixBinaryWrapping {
	@SuppressWarnings({ "unchecked", "rawtypes" })
	static public <E extends LedixBinary, T> E wrapLedixBinary(T tt, RedisConfigType redisConfigType, ProviderConfigType providerConfigType) {

		LedixBinaryOnCloseInvocationHandler<T> handler = new LedixBinaryOnCloseInvocationHandler<T>(tt, redisConfigType, providerConfigType);
		Class[] interfaces = null;
		{
			Class<?>[] implementedInterfaces = tt.getClass().getInterfaces();
			interfaces = new Class[implementedInterfaces.length + 1];
			interfaces[0] = LedixBinary.class;
			System.arraycopy(implementedInterfaces, 0, interfaces, 1, implementedInterfaces.length);
		}
		E proxiedObj = (E) Proxy.newProxyInstance(tt.getClass().getClassLoader(), interfaces, handler);

		return proxiedObj;
	}

	public static class LedixBinaryOnCloseInvocationHandler<T> implements InvocationHandler {
		// 代理类中的真实对象
		private RedisConfigType redisConfigType;
		private ProviderConfigType providerConfigType;
		private T originalObj;
		// private T proxiedObj;

		// 构造函数，给我们的真实对象赋值
		public LedixBinaryOnCloseInvocationHandler(T originalObj, RedisConfigType redisConfigType, ProviderConfigType providerConfigType) {
			this.redisConfigType = redisConfigType;
			this.providerConfigType = providerConfigType;
			this.originalObj = originalObj;
		}

		@Override
		public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
			if (originalObj == null) {
				throw new RedisException("Connection is deallocated and cannot be used anymore.");
			}

			if (method.getName().equals("getOriginCommands")) {
				return originalObj;
			}

			if (method.getName().equals("getRedisConfigType")) {
				return redisConfigType;
			}

			if (method.getName().equals("getProviderConfigType")) {
				return providerConfigType;
			}

			if (method.getName().equals("close")) {
				originalObj = null;
				return null;
			}

			Object invoke = method.invoke(originalObj, args);
			return invoke;
		}

	}

}
